iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 14
0
自我挑戰組

.net 後端起手式 30天認識 C# 系列 第 14

DAY 14 類別(三)

  • 分享至 

  • xImage
  •  

類別

上次講的類別都屬於參考型別,今天會介紹實質型別的類別,如果忘記型別差異的話,可以回去看第二天的文章。

結構 struct

結構包含建構函式、常數、欄位、方法、屬性、索引子、運算子、事件和巢狀型別,不過如果需要數個這類成員,您應該考慮以類別來取代類型。

結構的用法與 class 相似,但結構使用時,無法初始化屬性,在下方用 class 示範如何初始化屬性

class Program {
  static void Main (string[] args) {
    Member member = new Member (1, "Mio");
    member.Print ();
    Memberc memberc = new Memberc ();
    memberc.Print ();
  }
}
struct Member {
  public Member (int id, string name) {
    ID = id;
    Name = name;
  }
  public int ID { get; }
  public string Name { get; }
  public void Print () {
    Console.WriteLine ($"ID: {id}, Name: {name}");
  }
}
class Memberc {
  public Memberc () { }
  public Memberc (int id, string name) {
    ID = id;
    Name = name;
  }
  public int ID { get; } = 1;
  public string Name { get; } = "Mio";
  public void Print () {
    Console.WriteLine ($"ID: {ID}, Name: {Name}");
  }
}

也就是當今天沒有傳入任何參數時,則會預設是 ID = 0, Name = Mio,隨便舉例而已。get 是存取子,還有一個是 set,如果只有 get 就是唯讀,只有 set 就是唯寫,詳細操作可以看下方連結。

結構往往是用在不可變的狀態下,像範例中的屬性成員是唯讀的,不能去修改。

列舉

包含一組稱為列舉程式清單之具名常數的不同類型

以資料庫連線狀態來舉例,假設連線狀態有未連接、嘗試連接與連接中三種狀態

如果不使用列舉,我們稱狀態為 0, 1, 2

int connectionState;
// ...
switch (connectionState) {
  case 0:
    // ...
    break;
  case 1:
    // ...
    break;
  case 2:
    // ...
    break;
}

使用列舉後

ConnectionState connectionState;
// ...
switch (connectionState) {
  case connectionState.Disconnected:
    // ...
    break;
  case connectionState.Connecting:
    // ...
    break;
  case connectionState.Connected:
    // ...
    break;
}

可讀性是不是差很多呢?兩者在運行時效能完全一樣,列舉的關鍵在於編譯時能宣告一組可以透過名稱來使用的整數值

enum ConnectionState {
  Disconnected,
  Connecting,
  Connected
}

在使用時,需要加入列舉名稱前綴如ConnectionState.Connected,如果沒有任何預設值的話,列舉的數值從 0 開始排,也就是說

static void Main (string[] args) {
  Console.WriteLine ($"Name = {MyEnum.A}, Value = {(int)MyEnum.A}");
  Console.WriteLine ($"Name = {MyEnum.B}, Value = {(int)MyEnum.B}");
  Console.WriteLine ($"Name = {MyEnum.C}, Value = {(int)MyEnum.C}");
  Console.ReadKey ();
}
enum MyEnum {
  A,
  B,
  C
}

但如果今天加入預設值後

static void Main (string[] args) {
  Console.WriteLine ($"Name = {MyEnum.A}, Value = {(int)MyEnum.A}");
  Console.WriteLine ($"Name = {MyEnum.B}, Value = {(int)MyEnum.B}");
  Console.WriteLine ($"Name = {MyEnum.C}, Value = {(int)MyEnum.C}");
  Console.WriteLine ($"Name = {MyEnum.D}, Value = {(int)MyEnum.D}");
  Console.WriteLine ($"Name = {MyEnum.E}, Value = {(int)MyEnum.E}");
  Console.ReadKey ();
}
enum MyEnum {
  A,
  B = 8,
  C = 6,
  D,
  E
}

可以自己玩玩看,列舉不是只有 int 而已,也可以宣告成 short 如

enum MyEnum : short {
  A,
  B = 8,
  C = 6,
  D,
  E
}

除了像是這種分開的狀態外,也會使用在可疊加狀態的,像是一個標誌來使用,以 System.IO.FileAttributes 舉例

[Flags]
public enum FileAttributes
{
  ReadOnly = 1, // 1 << 0  0000001   
  Hidden = 2,   // 1 << 1  0000010
  System = 4,   // 1 << 2  0000100
  Directory = 8,// 1 << 3  0001000
  /*
   * 以下省略
  */
}

題外話:在設定初始值時,也可以像右邊的移位運算子(<<),會比較整齊。

這種列舉可以想成是二進位的加減,當你今天需要多重狀態時,就可以使用 OR 運算子來疊加,假設我今天需要前面兩種狀態的話,如

static void Main (string[] args) {
  System.IO.FileAttributes FA = System.IO.FileAttributes.Hidden | System.IO.FileAttributes.ReadOnly;
  Console.WriteLine ($"Name = {FA}, Value = {(int)FA}");
  Console.ReadKey ();
}

可以看到名稱很完整的印出了每個狀態,因為在使用這個列舉時有加一個 Attribute(屬性) [Flags],可以自己撰寫一個以二進位方式的列舉,加入這個屬性來看差異。

題外話:雖然中文都翻屬性,但我覺得有時候講起來很容易混淆,不知道有沒有路過的大大可以提通我更好的中文字詞。

一些小結論

今天把實質型別的類別做了個大概,本來在實務上是很少使用結構的,都是使用 class 類別來取代,所以在說類別時,往往就是指 class 了。而列舉就比較容易遇到,因為可以讓程式碼在讀的時候比較好懂。

感謝閱讀。

參考連結
struct (C# 參考) | Microsoft Docs
get (C# 參考) | Microsoft Docs
enum 關鍵字 (C# 參考) | Microsoft Docs


上一篇
DAY 13 介面
下一篇
DAY 15 類別(四)
系列文
.net 後端起手式 30天認識 C# 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言